import * as THREE from "three";
import { useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { useKeyboardControls } from "@react-three/drei";
import {
  CapsuleCollider,
  RapierRigidBody,
  RigidBody,
  vec3,
} from "@react-three/rapier";

const SPEED = 5; // 移动速度
const JUMP = 10; // 跳跃速度
const direction = new THREE.Vector3(); // 移动方向
const frontVector = new THREE.Vector3(); // 前后移动
const sideVector = new THREE.Vector3(); // 左右移动

let frame = 0; // 渲染帧数
let onGround = false; // 是否在地面

export default ({ log = false }) => {
  /*---------------------------声名变量-------------------------------*/
  const player = useRef<RapierRigidBody>(null);

  const [, get] = useKeyboardControls();

  /*---------------------------帧回调-------------------------------*/
  useFrame((state, delta) => {
    if (!player.current) return;
    frame += 1;
    // 获取键盘输入
    const { forward, backward, left, right, jump }: any = get();

    // 获取玩家位置
    const position = vec3(player.current.translation());

    // 更新相机位置
    state.camera.position.set(position.x, position.y + 0.75, position.z);

    // 获取移动方向
    frontVector.set(0, 0, backward - forward); // 前后移动
    sideVector.set(left - right, 0, 0); // 左右移动
    direction
      .subVectors(frontVector, sideVector)
      .normalize()
      .multiplyScalar(SPEED)
      .applyEuler(state.camera.rotation); // 以相机方向为基准

    // 跳跃
    if (jump && onGround) {
      onGround = false;
      player.current.applyImpulse({ x: 0, y: JUMP, z: 0 }, true);
    }

    // 移动
    const deltaPos = direction.clone().multiplyScalar(delta);
    player.current.setTranslation(position.add(deltaPos), true);

    // 打印
    if (
      (forward || backward || left || right || jump) &&
      frame % 10 === 0 &&
      log
    ) {
      console.log(`--------------${frame}---------------`);
      console.log("onGround", onGround);
      console.log("direction", direction);
      console.log("position", position);
    }
  });
  /*---------------------------模型渲染-------------------------------*/
  return (
    <RigidBody
      name="玩家"
      ref={player}
      colliders={false}
      mass={1}
      type="dynamic"
      position={[0, 10, 0]}
      enabledRotations={[false, false, false]}
      onCollisionEnter={({ manifold, other }) => {
        const result = manifold.solverContactPoint(0);
        if (!result) return;

        onGround = true;
        if (other.rigidBodyObject && log) {
          console.log("碰撞点： ", result);
          console.log("碰撞对象：", other.rigidBodyObject.name);
        }
      }}
    >
      <CapsuleCollider args={[0.75, 0.5]} />
    </RigidBody>
  );
};
